from fastapi import FastAPI, HTTPException, Request
from app.routers import recommendation, auth, chat 
from app.services.recommendation_service import RecommendationService
from app.services.maoyan_api_service import MaoyanApiService
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from contextlib import asynccontextmanager
import logging
import time
import uvicorn

# 导入配置
from app.config.settings import settings

# 导入数据库
from app.database.connection import init_db, check_connection

# 导入模型以确保表被创建
from app.models.session import Session, Message
from app.models.user import User, UserProfile
from app.models.movie import Movie

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# 全局服务实例
recommendation_service: RecommendationService = None

# 应用生命周期管理
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    logger.info("CineMind AI 后端服务启动中...")
    
    try:
        # 数据库初始化
        if check_connection():
            logger.info("数据库连接成功")
            init_db()
            logger.info("数据库初始化完成")
        else:
            logger.error("数据库连接失败")
            raise Exception("数据库连接失败")
        
        # 猫眼服务与推荐服务初始化
        global recommendation_service
        maoyan_service = MaoyanApiService()  # 实例化猫眼服务
        recommendation_service = RecommendationService(maoyan_service)  # 初始化推荐服务
        
        # 预加载热映电影数据（提升首次访问速度）
        await recommendation_service.get_hot_movies(20)
        
    except Exception as e:
        logger.error(f"应用启动失败: {e}")
        raise
    
    logger.info("CineMind AI 后端服务启动完成")
    
    yield
    
    # 关闭时执行
    logger.info("CineMind AI 后端服务关闭")

# 创建FastAPI应用
app = FastAPI(
    title=settings.app_name,
    description="CineMind AI - 智能影视推荐系统后端API",
    version=settings.version,
    docs_url="/docs" if settings.debug else None,
    redoc_url="/redoc" if settings.debug else None,
    lifespan=lifespan
)

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.cors_origins_list,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 添加可信主机中间件（生产环境）
if not settings.debug:
    app.add_middleware(
        TrustedHostMiddleware,
        allowed_hosts=settings.cors_origins_list
    )

# 请求日志中间件
@app.middleware("http")
async def log_requests(request: Request, call_next):
    """记录请求日志"""
    start_time = time.time()
    
    # 记录请求信息
    logger.info(f"请求开始: {request.method} {request.url}")
    
    try:
        response = await call_next(request)
        
        # 计算处理时间
        process_time = time.time() - start_time
        
        # 记录响应信息
        logger.info(
            f"请求完成: {request.method} {request.url} - "
            f"状态码: {response.status_code} - 耗时: {process_time:.3f}s"
        )
        
        # 添加处理时间到响应头
        response.headers["X-Process-Time"] = str(process_time)
        
        return response
        
    except Exception as e:
        # 记录异常
        process_time = time.time() - start_time
        logger.error(
            f"请求异常: {request.method} {request.url} - "
            f"异常: {str(e)} - 耗时: {process_time:.3f}s"
        )
        raise

# 全局异常处理
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    """请求验证异常处理器"""
    # 提取第一个验证错误的消息
    error_msg = "输入信息格式错误"
    if exc.errors():
        first_error = exc.errors()[0]
        if 'ctx' in first_error and 'error' in first_error['ctx']:
            # 提取自定义验证错误消息
            error_msg = str(first_error['ctx']['error'])
        elif 'msg' in first_error:
            error_msg = first_error['msg']
    
    logger.warning(f"请求验证失败: {error_msg} - 详细错误: {exc.errors()}")
    
    return JSONResponse(
        status_code=422,
        content={
            "detail": error_msg,
            "status_code": 422
        }
    )

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    """全局异常处理器"""
    logger.error(f"未处理的异常: {str(exc)}", exc_info=True)
    
    return JSONResponse(
        status_code=500,
        content={
            "detail": "服务器内部错误",
            "message": "请稍后重试或联系管理员"
        }
    )

@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    """HTTP异常处理器"""
    logger.warning(f"HTTP异常: {exc.status_code} - {exc.detail}")
    
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "detail": exc.detail,
            "status_code": exc.status_code
        }
    )

# 根路由
@app.get("/", summary="根路径")
async def root():
    """根路径"""
    return {
        "message": "欢迎使用 CineMind AI API",
        "version": settings.app_version,
        "docs": "/docs" if settings.debug else "文档已禁用",
        "status": "运行中"
    }

# 健康检查
@app.get("/health", summary="健康检查")
async def health_check():
    """健康检查"""
    try:
        # 检查数据库连接
        db_status = "正常" if check_connection() else "异常"
        
        return {
            "status": "正常",
            "database": db_status,
            "timestamp": time.time(),
            "version": settings.app_version
        }
    except Exception as e:
        logger.error(f"健康检查失败: {e}")
        return JSONResponse(
            status_code=503,
            content={
                "status": "异常",
                "error": str(e),
                "timestamp": time.time()
            }
        )

# 注册路由
app.include_router(auth.router, prefix="/api/v1")
app.include_router(chat.router, prefix="/api/v1")
app.include_router(recommendation.router, prefix="/api/v1")

# 开发环境启动
if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host=settings.host,
        port=settings.port,
        reload=settings.debug,
        log_level="info"
    )